model MoC {

  //@todo Effect, CT, and DT should be types rather than enums.

  /*******************************************************************************************************************\
   * MoC nodes                                                                                                       *
  \*******************************************************************************************************************/
  nodes {
    enum Effect {none, local, implicit}
    enum CT {none, removed, reordered, renamed, rephrased}

    abstract node class Infom {
      url   : string;
      xpath : string;

      effect : Effect  = Effect::none;
      ct : CT          = CT::none;
      purl : string    = "";
      pxp  : string    = "";  
    }
  }  
  /*******************************************************************************************************************\
   * MoC edges                                                                                                       *
  \*******************************************************************************************************************/
  edges {
    enum DT {ident, name, position, literal, size, url}

    abstract directed edge class Dependency connect Infom -> Infom {
      via: DT;
    }

    // directed:
    //edge class dependsOn extends Dependency connect Infom[+] -> Infom[+];
    edge class requiredBy extends Dependency connect Infom[+] -> Infom[+];  

    // undirected:
    edge class correlatesWith extends Dependency connect Infom[+] -> Infom[+];
  }
  
  /*******************************************************************************************************************\
   * MoC equivs                                                                                                      *
  \*******************************************************************************************************************/
  equivs {
    // not yet implemented
  }  
  
  /*******************************************************************************************************************\
   * MoC rules                                                                                                       *
  \*******************************************************************************************************************/
  rules {
  
    // Change type markers
    
    rule markRemoved(v: Infom) {
      modify {
        eval {
          v.effect = Effect::local;
          v.ct     = CT::removed;
        } 
      }
    }
    
    rule markReordered(v: Infom) {
      modify {
        eval {
          v.effect = Effect::local;
          v.ct     = CT::reordered;
        } 
      }
    }
    
    rule markRenamed(v: Infom) {
      modify {
        eval {
          v.effect = Effect::local;
          v.ct     = CT::renamed;
        } 
      }
    }
    
    rule markRephrased(v: Infom) {
      modify {
        eval {
          v.effect = Effect::local;
          v.ct     = CT::rephrased;
        } 
      }
    }
        
    // Change type rippling with respect to dependency types
    
    /* A deletion affects all dependents independent of
     * actual dependency type.
     */
    rule rippleRemoved {
      provider:Infom -:requiredBy-> dependent:Infom;
      if { provider.ct == CT::removed; }
      if { dependent.effect == Effect::none; }
      modify {
        eval {
          dependent.effect = Effect::implicit;
          dependent.ct     = provider.ct;
          dependent.purl   = provider.url;
          dependent.pxp    = provider.xpath;
        }
      }
    }
    
    /* A rephrasing only affects dependents connected
     * via a literal dependency.
     */
    rule rippleRephrased {
      provider:Infom -d:requiredBy-> dependent:Infom;
      if { provider.ct == CT::rephrased; }
      if { dependent.effect == Effect::none; }
      if { d.via == DT::literal; }
      modify {
        eval {
          dependent.effect = Effect::implicit;
          dependent.ct     = provider.ct;
          dependent.purl   = provider.url;
          dependent.pxp    = provider.xpath;
        }
      }
    }
    
    // Slurp affected (local and implicit) INFOMs
    
    rule slurp {
      x: Infom;
      negative {
        if { x.effect == Effect::local || x.effect == Effect::implicit; }
      }
      replace {}
    }
        
  }
  
}
